from django.utils import timezone
from rest_framework import serializers
import logging
from django.db.models import Sum
import tsl_backend.frontend_api.models.workorder as workorders
import tsl_backend.frontend_api.models.route as routes
import tsl_backend.frontend_api.models.order_routing as order_routing
import tsl_backend.users.models as users
import tsl_backend.common as common

class RecordSerializer(serializers.ModelSerializer):
    class Meta:
        model = order_routing.Record
        fields = "__all__"


class WorkerActionSerializer(serializers.ModelSerializer):
    account_pk = serializers.IntegerField()

    class Meta:
        model = order_routing.WorkerActionRecord
        fields = ['action', 'worker_record', 'account_pk']

    def create(self, validated_data):
        # print(validated_data)
        worker_record_obj=validated_data.get('worker_record')

        editable, last_workactionrecord_obj=common.check_worker_record_editable(worker_record_obj)
        if not editable:
            logging.info("Worker record is not editable.")
            return None

        account_obj=users.Account.objects.get(pk=validated_data.get('account_pk'))
        if not account_obj.role.name=="WORKER":
            logging.warn(f"User {account_obj} is {account_obj.role.name}, not worker. Fail to update worker action record.")
            return None
 
        worker_record_obj.account=account_obj
        worker_record_obj.save(update_fields={'account'})
        logging.info(f"Update account to {worker_record_obj.account} for order {worker_record_obj}")

        # # get last record 
        # last_workactionrecord_obj = order_routing.WorkerActionRecord.objects.filter(worker_record=worker_record_obj).last()

        workactionrecord_obj=order_routing.WorkerActionRecord.objects.create(action=validated_data.get('action'),
                                                        worker_record=worker_record_obj)
        record_obj=workactionrecord_obj.worker_record.record_set.all().get()
        
        # Update RouteDetail status
        if workactionrecord_obj.action==1:
            logging.info(f"Worker submits work to Open")
            common.update_route_status(record_obj.route_detail, 2)

            if last_workactionrecord_obj:
                # calculate WorkerRecord work_duration, pause_duration
                if last_workactionrecord_obj.action==2:
                    logging.info(f"Worker resumes work. Calculate the pause duration")
                    diff = workactionrecord_obj.time - last_workactionrecord_obj.time
                    record_obj.worker.pause_duration+=diff
                    record_obj.worker.save(update_fields={"pause_duration"})
                    logging.info(f"Update worker {workactionrecord_obj} pause_duration to {record_obj.worker.pause_duration}")
        
        elif workactionrecord_obj.action==2:
            logging.info(f"Worker submits work to In Progress ")
            common.update_route_status(record_obj.route_detail, 2)

        else:
            # check if flow end
            logging.info(f"Worker submits work to Completion")
            last_step=common.check_current_flow_end(record_obj.route_detail, "scan_and_record")

            logging.info(f"Is it last step of flow? {last_step}")
            if last_step:
                common.update_route_detail_status(workactionrecord_obj.worker_record)
                # common.update_route_status(record_obj.route_detail, 3)

            # update work_count in workerRecord
            common.update_worker_count(record_obj.worker)

        # sum up the working duration
        if last_workactionrecord_obj:
            diff = workactionrecord_obj.time - last_workactionrecord_obj.time
            record_obj.worker.work_duration+=diff
            record_obj.worker.save(update_fields={"work_duration"})
            logging.info(f"Update worker {workactionrecord_obj} work_duration to {record_obj.worker.work_duration}")
        
        # update holder name
        common.update_holder_account(account_obj, record_obj.route_detail.order_route)
        return workactionrecord_obj


class QcFailedSerializer(serializers.ModelSerializer):
    class Meta:
        model = order_routing.QcFailed
        fields = ['reason', 'quantity']

class QCActionSerializer(serializers.ModelSerializer):
    order = serializers.CharField(max_length=20, read_only=True)
    failed_details=QcFailedSerializer(many=True, source='check_record_failed_details_set.related_model')
    # received_at = serializers.DateTimeField(required=False, format="%Y.%m.%d %H:%M:%S.%f", input_formats=["%Y.%m.%d %H:%M:%S.%f"])

    class Meta:
        model = order_routing.CheckRecord
        exclude = ['check_type', 'work_count']

    
    def update(self, instance, validated_data):
        failed_details_data = validated_data.pop('check_record_failed_details_set', None)

        if validated_data.get('check_at'):
            validated_data['check_at']=timezone.now()
        if failed_details_data:
            if failed_details_data["related_model"]:
                old_failed_details=instance.failed_details.all()
                old_failed_details.delete()
                for failed_detail_data in failed_details_data["related_model"]:
                    failed_detail=order_routing.QcFailed.objects.create(reason=failed_detail_data["reason"], quantity=failed_detail_data["quantity"])
                    instance.failed_details.add(failed_detail)
                
                validated_data['work_count'] = instance.work_count + 1
        instance = super().update(instance, validated_data)

        account_obj=validated_data.get('account')
        if instance.check_type==1:
            order_route_obj=instance.qc_check.last().route_detail.order_route
            record=instance.qc_check.last()
            
            #  auto-complete worker job
            common.complete_worker_job(record)

        elif instance.check_type==2:
            order_route_obj=instance.leader_check.last().route_detail.order_route
            record=instance.leader_check.last()
        elif instance.check_type==3:
            order_route_obj=instance.stone_check.last().route_detail.order_route
            record=instance.stone_check.last()
        else:
            logging.info(f"User {account_obj} role is {account_obj.role.name}, not QC")
            order_route_obj=None
            record=None
        if order_route_obj:
            common.update_holder_account(account_obj, order_route_obj)
        
        # if qc result fail, create new record
        if instance.failed:
            logging.info(f"{instance} result is failed. Create new record for routing. Re-do the flow again.")
            route_detail_obj=record.route_detail
            new_record_obj=common.create_order_flow_record(route_detail_obj)
            logging.info(f"{new_record_obj} is created.")


        return instance

    def check_fail_reason(self):
        logging.info(f"self.validated_data: {self.validated_data}")
        valid=True
        failed_details_data = self.validated_data.get('check_record_failed_details_set', None)
        res_failed = self.validated_data.get('failed')
        if res_failed==True:
            if not failed_details_data["related_model"]:
                logging.info(f"No fail reason is selected")
                valid=False
        return valid


class DetailSerializer_del(serializers.ModelSerializer):
    class Meta:
        model = workorders.Detail
        fields = "__all__"
    
    def to_representation(self, instance):
        data = super().to_representation(instance)
        grouped_data = {
            "status": {  # TODO: what's the different between these and the one in routingHistory
                    "worker_name": "x",
                    "worker_record_time": "x",
                    "holder_name": "x",
                    "holder_record_time": "x",
                },
            "order": {
                    "orderNo": data.pop('order'),
                    "dueDate": data.pop('due_date'),
                    "orderQty": data.pop('quantity'),
                    "goodsType": data.pop('goods_type'),
                    "description": data.pop('description'),
                    "ringType": data.pop('ring_type'),
                    "goldType": data.pop('gold_type'),
                    "site": data.pop('site'),
                    "stoneReadyDate": data.pop('ready_date'),
                    "flowerNo": data.pop('flower_count'),
                    "posType": data.pop('pos'),
                    "fgArticle": data.pop('master'), #route_master.fg_article,  
                    "designNum": data.pop('design'),
                    "mouldNo": data.pop('mould'),
                },
            "design": {
                "blackPicUrl": data.pop('black_pic_url'),
                "productRemark": data.pop('remark'),
                "effect": data.pop('effect'),
                "productMarkContent": data.pop('product_mark_content'),
                "productMarkFont": data.pop('product_mark_font'),
                "productMarkDesc": data.pop('product_mark_description'),
            },
            "prod": {
                "prodRemark": None, #prodRemark,
                "stoneInfo": None, #standard_boms_data,
                "stoneIssue": "x",  # TODO: cannot find reference to Stone Issue?
                "actualBom": {
                    "totalQty": data.pop('total_count'),  
                    "totalCTCnt": data.pop('total_ct'),  
                    "totalWeight": data.pop('total_gram'), 
                    "stoneInfo": None #actualbom_data
                }
            },
            "article": None#article,
        }
        return grouped_data

class MasterSerializer(serializers.ModelSerializer):
    class Meta:
        model = routes.Master
        fields = ["fg_article"]

class DetailSerializer(serializers.ModelSerializer):
    due_date = serializers.DateTimeField(format="%Y.%m.%d")
    updated_due_date = serializers.DateTimeField(format="%Y.%m.%d")
    ready_date = serializers.DateTimeField(format="%Y.%m.%d")
    master_name = serializers.CharField(source='master', read_only=True)

    class Meta:
        model = workorders.Detail
        fields = "__all__"  
    
    def to_representation(self, instance):
        data = super().to_representation(instance)
        dueDate = data.pop('due_date')
        updatedDueDate = data.pop('updated_due_date')

        if dueDate==updatedDueDate:
            updatedDueDate=None
        source = data.pop('source') if data['source'] else ''
        productMarkDesc:str = data.pop('product_mark_description')
        
        ### 由append来分隔, 前面的放刻印说明, 后面放刻印效果
        if "append" in productMarkDesc:
            product_mark_desc_split = productMarkDesc.split('append')
            product_mark_desc = product_mark_desc_split[0]
            product_mark_effect = product_mark_desc_split[1]
        else:
            product_mark_desc = productMarkDesc
            product_mark_effect = ""
            
        grouped_data = {
            "status": {},
            "order": {
                    "orderNo": data.pop('order'),
                    "dueDate": dueDate,
                    "updatedDueDate": updatedDueDate,
                    "orderQty": data.pop('quantity'),
                    "goodsType": data.pop('goods_type'),
                    "description": data.pop('description'),
                    "ringType": data.pop('ring_type'),
                    "goldType": data.pop('gold_type'),
                    "site": data.pop('site'),
                    "stoneReadyDate": data.pop('ready_date'),
                    "flowerNo": data.pop('flower_count'),
                    "posType": data.pop('pos'),
                    "fgArticle": data.pop('ori_fg_article'), #route_master.fg_article,  
                    "designNum": data.pop('design'),
                    "mouldNo": data.pop('mould'),
                    "source": (instance.get_source_display()+f"[{source}]") if source else '',
                    "source_code":  source,
                },
            "design": {
                "blackPicUrl": data.pop('black_pic_url'), 
                "productRemark": data.pop('remark'),
                "effect": data.pop('effect'),
                "productMarkContent": data.pop('product_mark_content'),
                "productMarkFont": data.pop('product_mark_font'),
                "productMarkDesc": productMarkDesc,
                "product_mark_desc": product_mark_desc,
                "product_mark_effect": product_mark_effect,
            },
            "prod": {
                "prodRemark": None, #prodRemark,
                "stoneInfo": None, #standard_boms_data,
                "stoneIssue": data.pop('stone_issue'),
                "actualBom": {
                    "totalQty": data.pop('total_count'),  
                    "totalCTCnt": data.pop('total_ct'),  
                    "totalWeight": data.pop('total_gram'), 
                    "stoneInfo": None #actualbom_data
                }
            },
            "article": None#article,
        }
        return grouped_data

class StandardbomSerializer(serializers.ModelSerializer):
    class Meta:
        model = workorders.ProductionStandardBOM
        fields = ['article', 'article_description', 'qty', 'weight']


class ActualbomSerializer(serializers.ModelSerializer):
    class Meta:
        model = workorders.ProductionActualBOM
        fields = ['seq', 'laser_mark','article', 'is_main_stone', 'stone_cert', 'stone_color', 'stone_clarity', 'weight', 'unit', 'quantity']

class ProductionRemarkSerializer(serializers.ModelSerializer):
    class Meta:
        model = order_routing.ProductionRemark
        fields = ['pk', 'type', 'remark']

class ProductionRemarkAnsSerializer(serializers.ModelSerializer):
    prod_remark = ProductionRemarkSerializer()
    config_pk = serializers.IntegerField(source='pk')
    ans = serializers.IntegerField(source='production_remark_ans')
    
    class Meta:
        model = order_routing.ProductionRemarkAns
        fields = ['config_pk', 'prod_remark', 'ans']

    def to_representation(self, instance):
        ret = super().to_representation(instance)
        prod_remark_data = ret.pop('prod_remark')
        ret.update(prod_remark_data)
        return ret

class DifficultySerializer(serializers.ModelSerializer):
    class Meta:
        model = routes.Difficulty
        fields = ["pk", "name"]

class FlowSerializer(serializers.ModelSerializer):
    class Meta:
        model = users.Flow
        fields = ["pk", "chinese_name"]
        
class RouteDetailSerializer(serializers.ModelSerializer):
    flow = FlowSerializer()
    difficulty = DifficultySerializer()
    qty = serializers.IntegerField(source='quantity')
    weight = serializers.IntegerField(source='pk')  # TODO: missing Weight
    
    class Meta:
        model = order_routing.RouteDetail
        fields = ['flow', 'difficulty', 'qty', 'weight', 'seq', 'dispatcher']

    def to_representation(self, instance):
        ret = super().to_representation(instance)
        ret['flow'] = ret['flow']['chinese_name']
        ret['difficulty'] = ret['difficulty']['name']
        return ret


class OrderViewRouteDetailSerializer(serializers.ModelSerializer):
    flow = FlowSerializer()
    difficulty = DifficultySerializer()
    qty = serializers.IntegerField(source='quantity')
    
    class Meta:
        model = order_routing.RouteDetail
        fields = ['pk', 'flow', 'difficulty', 'qty', 'seq', 'dispatcher', 'primary_stone_setting', 'secondary_stone_setting', 'consumption_percentage', 'worker_fee', 'status', 'order_route']

    def to_representation(self, instance):
        ret = super().to_representation(instance)
        ret['flow'] = ret['flow']['chinese_name']
        ret['difficulty'] = ret['difficulty']['name'] if ret['difficulty'] else None
        ret['status'] = instance.get_status_display()
        ret['weight'] = instance.actual_weight.filter(state__in=[1, 3]).aggregate(sum_weight=Sum('actual_weight'))['sum_weight']

        # PF不显示重量, 保留2为小数
        if ret["flow"] == "PF":
            ret["weight"] = ""
        elif ret["weight"]:
            ret['weight'] = f"{ret['weight']:.2f}"

        return ret

class OrderRouteCheckFlowChangeSerializer(serializers.ModelSerializer):
    flow = FlowSerializer()
    class Meta:
        model = order_routing.RouteDetail
        fields = ['pk', 'flow', 'status']

    def to_representation(self, instance):
        ret = super().to_representation(instance)
        ret['flow'] = ret['flow']['pk']
        return ret

class QcFailedReasonSerializer(serializers.ModelSerializer):
    class Meta:
        model = order_routing.QcFailedReason
        fields = ["pk", "reason", "unit"]


class StoneMountSettingSerializer(serializers.ModelSerializer):
    class Meta:
        model = routes.StoneMountSetting
        fields = ["pk", "name"]


class UpdateRouteDetailSerializer(serializers.ModelSerializer):
    class Meta:
        model = order_routing.RouteDetail
        exclude = ["dispatcher"]



# class DjangoUserSerializer(serializers.ModelSerializer):
#     class Meta:
#         model = users.User
#         fields = ["cnName"]

# class AccountSerializer(serializers.ModelSerializer):
#     django_user = DjangoUserSerializer()
#     class Meta:
#         model = users.Account
#         fields = ["django_user"]

# class WorkerRecordSerializer(serializers.ModelSerializer):
#     account = AccountSerializer()
#     class Meta:
#         model = order_routing.WorkerRecord
#         fields = ["account", "work_count"]


# class CheckRecordSerializer(serializers.ModelSerializer):
#     account = AccountSerializer()
#     class Meta:
#         model = order_routing.CheckRecord
#         fields = ["account", "check_at"]
        
# class RecordSerializer(serializers.ModelSerializer):
#     worker = WorkerRecordSerializer()
#     qc_check = CheckRecordSerializer()
#     leader_check = CheckRecordSerializer()
#     stone_check = CheckRecordSerializer()
#     route_detail = RouteDetailSerializer()
#     startDate = serializers.DateTimeField(source="time")
    
#     class Meta:
#         model = order_routing.Record
#         fields = ['worker', 'startDate', 'qc_check', 'leader_check', 'stone_check', 'route_detail']

#     def to_representation(self, instance):
#         ret = super().to_representation(instance)
#         ret['workCount'] = ret['work_count']
#         ret['flow'] = ret['route_detail']['flow']
#         ret['workerName'] = ret['worker']['account']['django_user']['cnName']
#         ret['flow'] = ret['route_detail']['flow']
#         return ret
    
